package com.sky.service.impl;

import com.sky.dto.AdjustmentCreateDTO;
import com.sky.dto.TransactionPageQueryDTO;
import com.sky.dto.WithdrawalPageQueryDTO;
import com.sky.dto.CreateWithdrawalDTO;
import com.sky.dto.ApproveWithdrawalDTO;
import com.sky.dto.RejectWithdrawalDTO;
import com.sky.entity.FinancialTransaction;
import com.sky.entity.MerchantWithdrawal;
import com.sky.mapper.FinancialTransactionMapper;
import com.sky.mapper.MerchantWithdrawalMapper;
import com.sky.mapper.OrderMapper;
import com.sky.mapper.MerchantMapper;
import com.sky.mapper.StudentMapper;
import com.sky.entity.Order;
import com.sky.entity.Student;
import com.sky.entity.Merchant;
import com.sky.result.PageResult;
import com.sky.service.FinanceService;
import com.sky.vo.IdVO;
import com.sky.vo.TransactionRecordVO;
import com.sky.vo.TransactionSummaryVO;
import com.sky.vo.WithdrawalVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.ByteArrayInputStream;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.HashMap;
import java.util.Map;

@Service
public class FinanceServiceImpl implements FinanceService {

    @Autowired
    private FinancialTransactionMapper transactionMapper;

    @Autowired
    private MerchantWithdrawalMapper withdrawalMapper;

    // 新增：用于富化收入/支出详情
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private MerchantMapper merchantMapper;
    @Autowired
    private StudentMapper studentMapper;

    @Override
    public PageResult getTransactionPage(TransactionPageQueryDTO dto) {
        // 解析时间与分页
        LocalDateTime startTime = parseDateTime(dto.getStartTime());
        LocalDateTime endTime = parseDateTime(dto.getEndTime());
        int page = dto.getPage() != null ? dto.getPage() : 1;
        int pageSize = dto.getPageSize() != null ? dto.getPageSize() : 10;
        int start = (page - 1) * pageSize;

        // 组装查询参数（与XML中的key保持一致）
        Map<String, Object> params = new HashMap<>();
        params.put("merchantId", dto.getMerchantId());
        params.put("direction", dto.getDirection());
        params.put("category", dto.getCategory());
        params.put("orderId", dto.getOrderId());
        params.put("withdrawalId", dto.getWithdrawalId());
        params.put("startTime", startTime);
        params.put("endTime", endTime);
        params.put("start", start);
        params.put("pageSize", pageSize);

        // 分页查询与统计
        List<FinancialTransaction> list = transactionMapper.selectByPage(params);
        long total = transactionMapper.countByPage(params);

        // 转换VO
        List<TransactionRecordVO> voList = list.stream().map(this::toTxVO).collect(java.util.stream.Collectors.toList());
        PageResult pr = new PageResult();
        pr.setTotal(total);
        pr.setRecords(voList);
        return pr;
    }

    @Override
    public TransactionSummaryVO getTransactionSummary(TransactionPageQueryDTO dto) {
        LocalDateTime startTime = parseDateTime(dto.getStartTime());
        LocalDateTime endTime = parseDateTime(dto.getEndTime());
        Long merchantId = dto.getMerchantId();
        BigDecimal income = transactionMapper.sumAmountByDirection("INCOME", merchantId, startTime, endTime);
        BigDecimal expense = transactionMapper.sumAmountByDirection("EXPENSE", merchantId, startTime, endTime);
        BigDecimal totalIncome = income != null ? income : BigDecimal.ZERO;
        BigDecimal totalExpense = expense != null ? expense : BigDecimal.ZERO;
        BigDecimal balance = totalIncome.subtract(totalExpense);
        return TransactionSummaryVO.builder()
                .totalIncome(totalIncome)
                .totalExpense(totalExpense)
                .balance(balance)
                .build();
    }

    @Override
    public IdVO createAdjustment(AdjustmentCreateDTO dto) {
        FinancialTransaction tx = new FinancialTransaction();
        tx.setMerchantId(dto.getMerchantId());
        tx.setDirection(dto.getAmount() != null && dto.getAmount().compareTo(BigDecimal.ZERO) >= 0 ? "INCOME" : "EXPENSE");
        tx.setCategory("ADJUSTMENT");
        tx.setAmount(dto.getAmount().abs());
        tx.setCurrency(dto.getCurrency());
        tx.setDescription(dto.getDescription());
        LocalDateTime occurred = parseDateTime(dto.getOccurredAt());
        tx.setOccurredAt(occurred != null ? occurred : LocalDateTime.now());
        tx.setCreatedByStudentId(null);
        transactionMapper.insert(tx);
        return new IdVO(tx.getId());
    }

    @Override
    public WithdrawalVO getWithdrawalById(Long id) {
        MerchantWithdrawal w = withdrawalMapper.selectById(id);
        return toWithdrawalVO(w);
    }


    // legacy helper for backward compatibility
    public IdVO createWithdrawal(Long merchantId, java.math.BigDecimal requestAmount, java.math.BigDecimal shareRatio, String requestTime) {
        CreateWithdrawalDTO dto = new CreateWithdrawalDTO();
        dto.setMerchantId(merchantId);
        dto.setRequestAmount(requestAmount);
        dto.setShareRatio(shareRatio);
        dto.setRequestTime(requestTime);
        return createWithdrawal(dto);
    }


    public String approveWithdrawal(Long id, BigDecimal payoutAmount) {
        ApproveWithdrawalDTO dto = new ApproveWithdrawalDTO();
        dto.setId(id);
        dto.setPayoutAmount(payoutAmount);
        return approveWithdrawal(dto);
    }


    public String rejectWithdrawal(Long id, String reason) {
        RejectWithdrawalDTO dto = new RejectWithdrawalDTO();
        dto.setId(id);
        dto.setReason(reason);
        return rejectWithdrawal(dto);
    }


    public com.sky.result.PageResult pageWithdrawals(int page, int pageSize, String status, Long merchantId, String startTime, String endTime) {
        java.time.LocalDateTime s = parseDateTime(startTime);
        java.time.LocalDateTime e = parseDateTime(endTime);
        int start = (page - 1) * pageSize;
        java.util.Map<String, Object> params = new java.util.HashMap<>();
        params.put("merchantId", merchantId);
        params.put("status", status);
        params.put("startTime", s);
        params.put("endTime", e);
        params.put("start", start);
        params.put("pageSize", pageSize);
        java.util.List<com.sky.entity.MerchantWithdrawal> list = withdrawalMapper.selectByPage(params);
        long total = withdrawalMapper.countByPage(params);
        java.util.List<com.sky.vo.WithdrawalVO> voList = list.stream().map(this::toWithdrawalVO).collect(java.util.stream.Collectors.toList());
        com.sky.result.PageResult pr = new com.sky.result.PageResult();
        pr.setTotal(total);
        pr.setRecords(voList);
        return pr;
    }

    @Override
    public ByteArrayInputStream exportFinanceData(TransactionPageQueryDTO dto) {
        LocalDateTime startTime = parseDateTime(dto.getStartTime());
        LocalDateTime endTime = parseDateTime(dto.getEndTime());
        int pageSize = dto.getPageSize() != null ? dto.getPageSize() : Integer.MAX_VALUE;
        Map<String, Object> params = new HashMap<>();
        params.put("merchantId", dto.getMerchantId());
        params.put("direction", dto.getDirection());
        params.put("category", dto.getCategory());
        params.put("orderId", dto.getOrderId());
        params.put("withdrawalId", dto.getWithdrawalId());
        params.put("startTime", startTime);
        params.put("endTime", endTime);
        params.put("start", 0);
        params.put("pageSize", pageSize);

        List<FinancialTransaction> list = transactionMapper.selectByPage(params);
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        StringBuilder sb = new StringBuilder();
        sb.append("序号,交易类型,类别,金额,时间,商家ID,订单ID,提现ID,备注\n");
        int i = 1;
        for (FinancialTransaction tx : list) {
            sb.append(i++)
              .append(',')
              .append("INCOME".equals(tx.getDirection()) ? "收入" : "支出").append(',')
              .append(tx.getCategory() != null ? tx.getCategory() : "").append(',')
              .append(tx.getAmount() != null ? tx.getAmount().setScale(2, java.math.RoundingMode.HALF_UP) : "").append(',')
              .append(tx.getOccurredAt() != null ? fmt.format(tx.getOccurredAt()) : "").append(',')
              .append(tx.getMerchantId() != null ? tx.getMerchantId() : "").append(',')
              .append(tx.getOrderId() != null ? tx.getOrderId() : "").append(',')
              .append(tx.getWithdrawalId() != null ? tx.getWithdrawalId() : "").append(',')
              .append(tx.getDescription() != null ? tx.getDescription().replace(","," ") : "")
              .append("\n");
        }
        byte[] bytes = sb.toString().getBytes(StandardCharsets.UTF_8);
        return new java.io.ByteArrayInputStream(bytes);
    }

    @Override
    public IdVO createWithdrawal(CreateWithdrawalDTO dto) {
        MerchantWithdrawal w = new MerchantWithdrawal();
        w.setMerchantId(dto.getMerchantId());
        w.setRequestAmount(dto.getRequestAmount());
        w.setShareRatio(dto.getShareRatio());
        w.setRequestTime(parseDateTime(dto.getRequestTime()));
        // 初始状态
        w.setStatus("PENDING");
        withdrawalMapper.insert(w);
        return new IdVO(w.getId());
    }

    @Override
    public String approveWithdrawal(ApproveWithdrawalDTO dto) {
        MerchantWithdrawal w = withdrawalMapper.selectById(dto.getId());
        if (w == null) return "NOT_FOUND";
        BigDecimal payout = dto.getPayoutAmount() != null ? dto.getPayoutAmount() : w.getRequestAmount();
        w.setStatus("COMPLETED");
        w.setProcessedTime(LocalDateTime.now());
        w.setPayoutAmount(payout);
        withdrawalMapper.update(w);

        // 记录支出流水
        FinancialTransaction tx = new FinancialTransaction();
        tx.setMerchantId(w.getMerchantId());
        tx.setWithdrawalId(w.getId());
        tx.setDirection("EXPENSE");
        tx.setCategory("WITHDRAWAL_PAYOUT");
        tx.setAmount(payout);
        tx.setCurrency("CNY");
        tx.setDescription("提现打款");
        tx.setOccurredAt(w.getProcessedTime());
        transactionMapper.insert(tx);
        return "OK";
    }

    @Override
    public String rejectWithdrawal(RejectWithdrawalDTO dto) {
        MerchantWithdrawal w = withdrawalMapper.selectById(dto.getId());
        if (w == null) return "NOT_FOUND";
        w.setStatus("REJECTED");
        w.setProcessedTime(LocalDateTime.now());
        w.setRejectReason(dto.getReason());
        withdrawalMapper.update(w);
        return "OK";
    }

    @Override
    public PageResult getWithdrawalPage(WithdrawalPageQueryDTO dto) {
        LocalDateTime startTime = parseDateTime(dto.getStartTime());
        LocalDateTime endTime = parseDateTime(dto.getEndTime());
        int page = dto.getPage() != null ? dto.getPage() : 1;
        int pageSize = dto.getPageSize() != null ? dto.getPageSize() : 10;
        int start = (page - 1) * pageSize;

        Map<String, Object> params = new HashMap<>();
        params.put("merchantId", dto.getMerchantId());
        params.put("status", dto.getStatus());
        params.put("startTime", startTime);
        params.put("endTime", endTime);
        params.put("start", start);
        params.put("pageSize", pageSize);

        List<MerchantWithdrawal> list = withdrawalMapper.selectByPage(params);
        long total = withdrawalMapper.countByPage(params);
        List<WithdrawalVO> voList = list.stream().map(this::toWithdrawalVO).collect(java.util.stream.Collectors.toList());
        PageResult pr = new PageResult();
        pr.setTotal(total);
        pr.setRecords(voList);
        return pr;
    }

    private TransactionRecordVO toTxVO(FinancialTransaction tx) {
        TransactionRecordVO vo = new TransactionRecordVO();
        vo.setId(tx.getId());
        vo.setMerchantId(tx.getMerchantId());
        vo.setWithdrawalId(tx.getWithdrawalId());
        vo.setOrderId(tx.getOrderId());
        vo.setDirection(tx.getDirection());
        vo.setCategory(tx.getCategory());
        vo.setAmount(tx.getAmount());
        vo.setCurrency(tx.getCurrency());
        vo.setDescription(tx.getDescription());
        vo.setOccurredAt(tx.getOccurredAt() != null ? tx.getOccurredAt().format(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME) : null);
        // 移除不存在的字段 createdByStudentId

        // 富化收入详情（订单）
        if (tx.getOrderId() != null) {
            Order order = orderMapper.selectById(tx.getOrderId());
            if (order != null) {
                String studentName = null;
                if (order.getStudentId() != null) {
                    Student stu = studentMapper.selectById(order.getStudentId());
                    if (stu != null) studentName = stu.getName();
                }
                String merchantName = null;
                if (order.getMerchantId() != null) {
                    Merchant m = merchantMapper.selectById(order.getMerchantId());
                    if (m != null) merchantName = m.getName();
                }
                BigDecimal unitPrice = null;
                if (order.getAmount() != null && order.getCopies() != null && order.getCopies() > 0) {
                    try {
                        unitPrice = order.getAmount().divide(new BigDecimal(order.getCopies()), 2, java.math.RoundingMode.HALF_UP);
                    } catch (Exception ignore) { }
                }
                TransactionRecordVO.IncomeDetailVO incomeDetail = new TransactionRecordVO.IncomeDetailVO(
                        order.getOrderNo(),
                        studentName,
                        merchantName,
                        order.getFileName(),
                        unitPrice,
                        order.getCopies(),
                        order.getAmount(),
                        order.getCompleteTime() != null ? order.getCompleteTime().format(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME) : null
                );
                vo.setIncomeDetail(incomeDetail);
            }
        }

        // 富化支出详情（提现）
        if (tx.getWithdrawalId() != null) {
            MerchantWithdrawal w = withdrawalMapper.selectById(tx.getWithdrawalId());
            if (w != null) {
                String merchantName = null;
                Merchant m = merchantMapper.selectById(w.getMerchantId());
                if (m != null) merchantName = m.getName();
                String time = w.getProcessedTime() != null ? w.getProcessedTime().format(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME)
                        : (w.getRequestTime() != null ? w.getRequestTime().format(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME) : null);
                TransactionRecordVO.ExpenseDetailVO expenseDetail = new TransactionRecordVO.ExpenseDetailVO(
                        merchantName,
                        w.getRequestAmount(),
                        w.getShareRatio(),
                        time,
                        w.getPayoutAmount()
                );
                vo.setExpenseDetail(expenseDetail);
            }
        }

        return vo;
    }

    private WithdrawalVO toWithdrawalVO(MerchantWithdrawal w) {
        WithdrawalVO vo = new WithdrawalVO();
        vo.setId(w.getId());
        vo.setMerchantId(w.getMerchantId());
        vo.setRequestAmount(w.getRequestAmount());
        vo.setShareRatio(w.getShareRatio());
        vo.setTotalIncomeSnapshot(w.getTotalIncomeSnapshot());
        vo.setBalanceSnapshot(w.getBalanceSnapshot());
        vo.setStatus(w.getStatus());
        vo.setRequestTime(w.getRequestTime());
        vo.setProcessedTime(w.getProcessedTime());
        vo.setProcessedByStudentId(w.getProcessedByStudentId());
        vo.setRejectReason(w.getRejectReason());
        vo.setPayoutAmount(w.getPayoutAmount());
        return vo;
    }

    private LocalDateTime parseDateTime(String s) {
        if (s == null || s.isEmpty()) return null;
        try {
            // ISO 带 T 的格式，如 2025-10-17T11:20:00 或带毫秒/偏移
            return LocalDateTime.parse(s, DateTimeFormatter.ISO_DATE_TIME);
        } catch (Exception e1) {
            try {
                // 无 T 的格式：yyyy-MM-dd HH:mm:ss
                String normalized = s.replace('T', ' ').replaceAll("Z$", "");
                return LocalDateTime.parse(normalized, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            } catch (Exception e2) {
                try {
                    // 解析为 Instant（如 2025-10-17T11:20:00Z），再转换为系统时区
                    java.time.Instant inst = java.time.Instant.parse(s);
                    return LocalDateTime.ofInstant(inst, java.time.ZoneId.systemDefault());
                } catch (Exception e3) {
                    return null;
                }
            }
        }
    }
}